package com.dianwang;

import com.dianwang.utils.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.bytedeco.opencv.presets.opencv_core;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;

public class TransformerDefectProcessor {
    public static void main(String[] args) throws Exception {
        //  加载Excel缺陷库
        String excelFilePath = "src/main/resources/defect_library1.xlsx";
        DefectLibrary defectLibrary = new DefectLibrary(excelFilePath);
        // 加载同义词词典
        SynonymDictionary synonymDict = new SynonymDictionary("synonyms.txt");
                DefectMatcherAdvanced defectMatcher = new DefectMatcherAdvanced(defectLibrary);
//        DefectMatcherAdvanced defectMatcher = new DefectMatcherAdvanced(defectLibrary,synonymDict);
        Processor processor = new Processor(defectMatcher);
        int k =10;
        String testInput = " 2024年10月28日，济南分部变电运维二班运维人员对聊城站进行带电检测时发现#2主变B相低压侧套管出线接线排存在异常发热点，热点温度38.1度，环境温度10度，正常设备温度12.80度，相对温差90.04%，温升28.1K,依据《DLT 664-2016 带电设备红外诊断应用规范》表H.1中电流致热设备缺陷诊断判据中金属部件与金属部件连接的接线和线夹90℃≤热点温度≤130℃或δ≥80%但热点温度未到达紧急缺陷程度值判定为严重缺陷要求，因此初步判定为严重缺陷。\n";
//        testInput = processor.preprocess(testInput);
        processor.process(testInput);
//        List<DefectMatcherAdvanced.ScoredDefect> topk = defectMatcher.getTopKDefectsWithMatchedTokens(testInput, k);
//        topk  = null;
        // 2) 计算成功率——假设“datasetForRate.xlsx”是你统计成功率用的数据文件
        String datasetForRate = "src/main/resources/dataset-new-2.xlsx";
        double successRate = computeSuccessRate(datasetForRate, defectMatcher, k);
        System.out.println(">>> 缺陷匹配成功率 = " + (successRate * 100) + "%");
        // 打印标题
        System.out.println("\n--- 测试 getTopKDefectsWithMatchedTokens ---");

        // 循环打印每条记录
        // 假设 topk 是 List<ScoredDefect>
//        for (int i = 0; i < topk.size(); i++) {
//            DefectMatcherAdvanced.ScoredDefect sd = topk.get(i);
//            DefectLibrary.Defect defect = sd.getDefect();
//            double score = sd.getScore();
//            List<String> matchedTokens = sd.getMatchedTokens();
//
//            StringBuilder sb = new StringBuilder();
////            sb.append("第").append(i + 1).append("名：").append("\n  匹配分值            : ").append(score).append("\n  匹配到的关键词       : ").append(matchedTokens).append("\n  缺陷ID             : ").append(defect.getId()).append("\n  缺陷描述名称        : ").append(defect.getDefectDescriptionName()).append("\n  缺陷分类名称        : ").append(defect.getDefectClassificationName()).append("\n  电压等级编码        : ").append(defect.getVoltageLevelCode()).append("\n  电压等级名称        : ").append(defect.getVoltageLevelName()).append("\n  设备类型编码        : ").append(defect.getEquipmentTypeCode()).append("\n  设备类型名称        : ").append(defect.getDeviceTypeName()).append("\n  作业类型编码        : ").append(defect.getWorkTypeCode()).append("\n  作业类型名称        : ").append(defect.getWorkType()).append("\n  设备种类编码        : ").append(defect.getDeviceCategoryCode()).append("\n  设备种类名称        : ").append(defect.getDeviceCategoryName()).append("\n  部件编码            : ").append(defect.getComponentCode()).append("\n  部件名称            : ").append(defect.getComponent()).append("\n  部件种类编码        : ").append(defect.getComponentCategoryCode()).append("\n  部件种类名称        : ").append(defect.getComponentCategoryName()).append("\n  部位编码            : ").append(defect.getPartCode()).append("\n  部位名称            : ").append(defect.getPartName()).append("\n  适用网省编码        : ").append(defect.getProvinceCode()).append("\n  适用网省名称        : ").append(defect.getProvinceName()).append("\n  缺陷描述编码        : ").append(defect.getDefectDescriptionCode()).append("\n  分类依据编码        : ").append(defect.getClassificationBasisCode()).append("\n  分类依据名称        : ").append(defect.getClassificationBasisName()).append("\n  缺陷分类编码        : ").append(defect.getDefectClassificationCode()).append("\n  缺陷分类名称        : ").append(defect.getDefectClassificationName()).append("\n-----------------------------------");
//            System.out.println(sb);
//        }
    }

    /**
     * 计算“匹配成功率”的示例函数，读取一份“dataset.xlsx”，其中包含以下列：
     * 0: part
     * 1: partType
     * 2: position
     * 3: defectDescription
     * 4: classificationBasis
     * 5: defectClassification
     * 6: defectContent (真正需要做匹配的“缺陷内容”)
     * <p>
     * 然后调用 defectMatcher.gettopkDefectsWithMatchedTokens(...) 获取前三条缺陷候选，
     * 若能在 topk 中找到 (component == part) && (defectDescriptionName == defectDescription)，即判定为“成功”。
     * 最终返回“成功率 = 成功条数 / 总条数”。
     *
     * @param datasetFilePath 你的测试集文件，比如 "C:/Users/wrt/Downloads/dataset.xlsx"
     * @param defectMatcher   你的缺陷匹配器
     * @return 成功率(0.0 ~ 1.0)
     */
    public static double computeSuccessRate(String datasetFilePath, DefectMatcherAdvanced defectMatcher, int k) {
        // 准备一个内部类结构来存放 Excel 行
        class Record {
            String device;          //对应 “设备类型”（期望值）
            String part;                // 对应“部件”（期望值）
            String partType;            // ...
            String position;            // ...
            String defectDescription;   // 期望的“缺陷描述”
            String classificationBasis; // ...
            String defectClassification;// ...
            String defectContent;       // 作为输入文本

            Record(String part, String partType, String position, String defectDescription, String classificationBasis, String defectClassification, String defectContent,String device) {
                this.device = device;
                this.part = part;
                this.partType = partType;
                this.position = position;
                this.defectDescription = defectDescription;
                this.classificationBasis = classificationBasis;
                this.defectClassification = defectClassification;
                this.defectContent = defectContent;
            }
        }

        List<Record> recordList = new ArrayList<>();

        // 1) 读取Excel
        try (FileInputStream fis = new FileInputStream(datasetFilePath); Workbook workbook = new XSSFWorkbook(fis)) {

            Sheet sheet = workbook.getSheetAt(0);  // 假设数据在第一个工作表
            Iterator<Row> rowIterator = sheet.iterator();

            // 跳过表头
            if (rowIterator.hasNext()) {
                rowIterator.next();
            }

            while (rowIterator.hasNext()) {
                Row row = rowIterator.next();

                // 这里的列索引需与你的Excel实际位置对应：

                String part = getCellString(row, 0);
                String partType = getCellString(row, 1);
                String position = getCellString(row, 2);
                String defectDescription = getCellString(row, 3);
                String classificationBasis = getCellString(row, 4);
                String defectClass = getCellString(row, 5);
                String defectContent = getCellString(row, 6);
                String device = getCellString(row, 7);
                // 若整行都空，则跳过
                if (part.isEmpty() && partType.isEmpty() && position.isEmpty() && defectDescription.isEmpty() && classificationBasis.isEmpty() && defectClass.isEmpty() && defectContent.isEmpty()) {
                    continue;
                }
                recordList.add(new Record(part, partType, position, defectDescription, classificationBasis, defectClass, defectContent,device));
            }
        } catch (FileNotFoundException e) {
            System.out.println("错误: 找不到文件 " + datasetFilePath);
            e.printStackTrace();
            return 0.0;
        } catch (IOException e) {
            System.out.println("错误: 读取文件时发生异常 " + datasetFilePath);
            e.printStackTrace();
            return 0.0;
        }

        // 2) 对每条记录做匹配
        int totalCount = recordList.size();
        int successCount = 0;

        for (Record r : recordList) {
            // 如果有文本预处理需求

            String preprocessed = TextPreprocessor.preprocess(r.defectContent + " " + r.device);

            // TopK匹配
            List<DefectMatcherAdvanced.ScoredDefect> topk = defectMatcher.getTopKDefectsWithMatchedTokens(preprocessed, k);

            // 判定是否成功：只要 topk 中存在一条 defect 的
            // ( == r.part) AND (defectDescriptionName == r.defectDescription)
            // 即视为成功
            boolean matched = false;
            for (DefectMatcherAdvanced.ScoredDefect sd : topk) {
                DefectLibrary.Defect d = sd.getDefect();
                if ((d.getPart().equals(r.part))&& d.getPosition().equals(r.position) && d.getDefectDescription().equals(r.defectDescription)) {
                    matched = true;
                    break;
                }
            }
            if (matched) {
                successCount++;
            }
        }

        // 3) 成功率
        if (totalCount == 0) {
            return 0.0;
        }
        return (double) successCount / totalCount;
    }

    /**
     * 读取单元格字符串值的简单辅助方法
     */
    private static String getCellString(Row row, int colIndex) {
        Cell cell = row.getCell(colIndex);
        if (cell == null) return "";
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue().trim();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    double d = cell.getNumericCellValue();
                    if (d == (long) d) {
                        return String.valueOf((long) d);
                    } else {
                        return String.valueOf(d);
                    }
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return "";
        }
    }

    /**
     * 简单的文本预处理，可根据需要调整
     */
    public static class TextPreprocessor {
        public static String preprocess(String input) {
            if (input == null) return "";
            // 替换 KV => kV
            input = input.replaceAll("KV", "kV").replaceAll("kv", "kV");
            // 去除多余空格
            input = input.trim().replaceAll("\\s+", " ");
            return input;
        }
    }

}
